<?php

class BPlugin_upload extends BPlugin
{
    
    /**
     * 支持的文件类型
     *
     * @access private
     * @var array
     */
    private $_types = array('png', 'jpg', 'jpeg', 'gif');
    
    /**
     * 文件大小最小值
     *
     * @access private
     * @var integer
     */
    private $_capacity_min = 0;
    
    /**
     * 文件大小最大值
     *
     * @access private
     * @var integer
     */
    private $_capacity_max = 10485760;
    
    /**
     * 图片目标目录
     *
     * @access private
     * @var string
     */
    private $_dir = './data/upload/';
    
    /**
     * 文件大小
     * @var int;
     */
    private $_size = '';
    
    /**
     * 取得/设定允许的图片类型
     *
     * @access public
     * @param $types mixed           
     * @return mixed
     */
    function type($types = null, $format = false)
    {
        if (is_null($types)) {
            $types = $this->_types;
            if ($format) {
                foreach($types as &$v) {
                    $v = '*.'.$v;
                }
                $types = implode(';', $types);
            }
            return $types;
        }
        if (is_array($types)&&$types) {
            $this->_types = $types;
        }
        return $this;
    }
    
    /**
     * 取得/设定文件大小限制
     *
     * @access public
     * @param $min integer           
     * @param $max integer           
     * @return object
     */
    function capacity($min = null, $max = null)
    {
        if (is_null($min)&&is_null($max)) {
            return array($this->formatSize($this->_capacity_min), $this->formatSize($this->_capacity_max));
        }
        $this->_capacity_min = $min;
        $this->_capacity_max = $max;
        return $this;
    }
    
    /**
     * 设置/取得文件保存路径
     *
     * @param $path string
     *            文件保存路径
     * @return mixed
     */
    function savepath($path = null)
    {
        if (is_null($path)) {
            return BLoader::PathName($this->_dir);
        } else {
            $this->_dir = $path;
            return $this;
        }
    }
    
    /**
     * 上传
     *
     * @access public
     * @param $name string
     *            表单中变量名
     * @param $n mixed
     *            第几个
     * @param $rpath bool
     *            返回实际地址
     * @return mixed
     */
    function upload($name, $n = null, $rpath = false)
    {
        $file = B::i()->plugin->request->files->{$name};
        $tmp_filename = $file['name'];
        $tmp_tmpname = $file['tmp_name'];
        $message = '';
        if (is_int($n)) {
            $tmp_filename = $tmp_filename[$n];
            $tmp_tmpname = $tmp_tmpname[$n];
        }
        $ext = strtolower(pathinfo($tmp_filename, PATHINFO_EXTENSION));
        if (!in_array($ext, $this->_types)) {
            $message .= '不允许的文件类型';
        }
        if (($size = filesize($tmp_tmpname))<$this->_capacity_min) {
            $message .= '大小超出限制，最小不得小于'.$this->_capacity_min;
        }
        if ($size>$this->_capacity_max) {
            $message .= '大小超出限制，最大不得大于'.$this->_capacity_max;
        }
        if (!$mkdir = $this->makeDir($ext)) {
            $message .= '文件夹创建失败';
        }
        if (!$message) {
            list($filename, $dir_rel, $flag) = $mkdir;
            if (!move_uploaded_file($tmp_tmpname, $this->savepath().$dir_rel.$filename)) {
                $message = '文件移动错误';
            } else {
                $this->_size = $size;
                $dir_rel = str_replace('\\', '/', $dir_rel);
                return ($rpath ? $this->savepath() : HOST_WWW.str_replace('./', '/', $this->_dir)).$dir_rel.$filename;
            }
        }
        
        return $message;
    }
    
    /**
     * 生成文件名, 若相应文件夹不存在则创建之
     *
     * @access public
     * @param $ext string
     *            文件后缀名
     * @return array
     */
    function makeDir($ext)
    {
        $flag = date('YmdHis').rand(1000, 9999);
        $filename = "{$flag}.$ext";
        $dir = $this->getAttachPath($flag);
        if ($this->mkPathTree($dir)) {
            return array($filename, $dir, $flag);
        } else {
            return false;
        }
    }
    
    /**
     * 取存储目录附加路径
     *
     * @param $flag string           
     * @return string
     */
    function getAttachPath($flag)
    {
        if (preg_match_all('/(\d{4})(\d{2})(\d{2})/x', $flag, $matches)) {
            return $matches[1][0].BLoader::SPACE_DIR.$matches[2][0].BLoader::SPACE_DIR;
        }
        return '';
    }
    
    /**
     * 分级创建目录
     *
     * @param $dir string           
     * @return bool
     */
    function mkPathTree($dir)
    {
        $dir = $this->savepath().BLoader::SPACE_DIR.$dir;
        $dir_tree = array_filter(explode(BLoader::SPACE_DIR, $dir));
        $tmp = BConfig::System()=='linux' ? BLoader::SPACE_DIR : '';
        if (count($dir_tree)>1) {
            foreach($dir_tree as $k=> $v) {
                $tmp .= rtrim($v.'', BLoader::SPACE_DIR).BLoader::SPACE_DIR;
                if (!file_exists($tmp)&&!mkdir($tmp, 0750)) {
                    return false;
                }
            }
        }
        return true;
    }
    
    /**
     * 根据文件标记取得上传目录
     *
     * @access public
     * @param $flag string
     *            文件标志
     * @param $path boolean
     *            是否要返回物理路径
     * @return string
     */
    function getDir($filename)
    {
        
        preg_match_all("/(\d{4})(\d{2})(\d{2})/x", $filename, $redirect);
        if ($redirect[2][0]) {
            return $this->_dirsavepath().$redirect[1][0].BLoader::SPACE_DIR.$redirect[2][0].BLoader::SPACE_DIR.$filename;
        }
        return null;
    }
    
    /**
     * 格式化文件大小
     *
     * @access public
     * @param integer $size
     * @return string
     */
    function formatSize($size)
    {
    	$prec = 3;
    	if ($size) {
    	    $size =  round(abs($size));
    	}
    	$units = array(' B', ' KB', ' MB', ' GB', ' TB');
    	if (!$size){
    		return str_repeat(' ', $prec). '0'. $units[0];
    	}
    	$unit = min(4, floor(log($size)/log(2)/10));
    	$size = $size*pow(2, -10*$unit);
    	$digi = $prec-1- floor(log($size)/log(10));
    	$size = round($size*pow(10, $digi))*pow(10, -$digi);
    	return $size.$units[$unit];
    }

}

?>
